//
//  Randomizer.h
//  CLUB_my_part
//
//  Created by Константин Денисов on 8/7/13.
//  Copyright (c) 2013 Константин Денисов. All rights reserved.
//

#ifndef CLUB_my_part_Randomizer_h
#define CLUB_my_part_Randomizer_h

//include, define and constants - begin


#include <math.h>
#include "Player.h"


const int Numder_Of_Near_Rating_Victims = 10;

const int Number_Of_Best_Rear_Metting_Victims = 3;

const int Deep_Of_Metting_Search = 1000;


//include and defines and constants - end
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//all classes, structures and function templates - begin


vector< pair< PPlayer, PPlayer > > Random_Killing_Pairs(vector < PPlayer > Players,
                                                        vector < PPlayer > &Remain_Players);
//pairs comes out as <Hunter, Victim>


//all classes and structures and function templates - end
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//all random functions - begin


//pairs comes out as <Hunter, Victim>
vector< pair< PPlayer, PPlayer > > Random_Killing_Pairs(vector < PPlayer > Players,
                                                        vector < PPlayer > &Remain_Players)
{
    vector< pair< PPlayer, PPlayer > > result;
    vector< PPlayer > hunters;
    vector< PPlayer > victims;
    
    for (int i = 0; i < Players.size(); ++i)
        if (Players[i]->now_type == Hunter)
            hunters.push_back(Players[i]);
        else
            victims.push_back(Players[i]);
    
    if ((victims.size() == 0) || (hunters.size() == 0))
        return result;
    
    //Find victim for every hunter
    
    PPlayer best_rating_victims[Numder_Of_Near_Rating_Victims];
    
    pair< PPlayer, int > best_rear_mitting_victims[Number_Of_Best_Rear_Metting_Victims];
    
    vector< pair< PPlayer, int > > victims_for_sort;
    
    vector< PPlayer > victims_for_random;
    
    int i = 0;
    for (i = 0; i < hunters.size(); ++i)
    {
        //Init
        
        for (int j = 0; j < Numder_Of_Near_Rating_Victims; ++j)
            best_rating_victims[j] = NULL;
        
        for (int j = 0; j < Number_Of_Best_Rear_Metting_Victims; ++j)
        {
            best_rear_mitting_victims[j].first = NULL;
            best_rear_mitting_victims[j].second = -1;
        }
        
        victims_for_sort.clear();
        
        victims_for_random.clear();
        
        //Find best victims with rating
     
        int j = 0;
        
        while ((j < Numder_Of_Near_Rating_Victims) && (j < victims.size()))
        {
            best_rating_victims[j] = victims[j];
            
            int k = j;
            while ((k > 0) && (fabs(best_rating_victims[k]->rating - hunters[i]->rating) <
                   fabs(best_rating_victims[k-1]->rating - hunters[i]->rating)))
            {
                swap(best_rating_victims[k], best_rating_victims[k-1]);
                --k;
            }
            
            ++j;
        }
        
        while (j < victims.size())
        {
            if (fabs(victims[j]->rating - hunters[i]->rating) <
                fabs(best_rating_victims[Numder_Of_Near_Rating_Victims - 1]->rating - hunters[i]->rating))
            {
                best_rating_victims[Numder_Of_Near_Rating_Victims - 1] = victims[j];
                
                int k = Numder_Of_Near_Rating_Victims - 1;
                while ((k > 0) && (fabs(best_rating_victims[k]->rating - hunters[i]->rating) <
                                   fabs(best_rating_victims[k-1]->rating - hunters[i]->rating)))
                {
                    swap(best_rating_victims[k], best_rating_victims[k-1]);
                    --k;
                }
            }
            
            ++j;
        }
        
        //If there is more victims with best rating
        
        if (best_rating_victims[min(Numder_Of_Near_Rating_Victims - 1, j - 1)]->rating ==
            best_rating_victims[0]->rating)
        {
            int neerest_rating = best_rating_victims[0]->rating;
            
            for (j = 0; j < victims.size(); ++j)
                if (victims[j]->rating == neerest_rating)
                    victims_for_sort.push_back(make_pair(victims[j], 0));
        }
        else
        {
            for (j = 0; j < Numder_Of_Near_Rating_Victims; ++j)
                if (best_rating_victims[j] != NULL)
                    victims_for_sort.push_back(make_pair(best_rating_victims[j], 0));
                else
                    break;
        }
        
        //Find last mittings
        
        for (j = 0; j < victims_for_sort.size(); ++j)
        {
            int k = (int)victims_for_sort[j].first->hunters.size() - 1;
            
            while ((k >= 0) && (victims_for_sort[j].first->hunters.size() - k < Deep_Of_Metting_Search) &&
                   (victims_for_sort[j].first->hunters[k] != hunters[i]->username))
                --k;
            
            if (k >= 0)
                victims_for_sort[j].second = (int)victims_for_sort[j].first->hunters.size() - k;
            else
                victims_for_sort[j].second = Deep_Of_Metting_Search;
        }
        
        //Find most rear-mitting victims between best rating.
        
        j = 0;
        
        while ((j < Number_Of_Best_Rear_Metting_Victims) && (j < victims_for_sort.size()))
        {
            best_rear_mitting_victims[j] = victims_for_sort[j];
            
            int k = j;
            
            while ((k > 0) && (best_rear_mitting_victims[k].second >
                   best_rear_mitting_victims[k - 1].second))
            {
                swap(best_rear_mitting_victims[k], best_rear_mitting_victims[k - 1]);
                
                --k;
            }
            
            ++j;
        }
        
        while (j < victims_for_sort.size())
        {
            if (victims_for_sort[j].second >
                best_rear_mitting_victims[Number_Of_Best_Rear_Metting_Victims - 1].second)
            {
                best_rear_mitting_victims[Number_Of_Best_Rear_Metting_Victims - 1] = victims_for_sort[j];
            
                int k = Number_Of_Best_Rear_Metting_Victims - 1;
            
                while ((k > 0) && (best_rear_mitting_victims[k].second >
                               best_rear_mitting_victims[k - 1].second))
                {
                    swap(best_rear_mitting_victims[k], best_rear_mitting_victims[k - 1]);
                
                    --k;
                }
            }
            
            ++j;
        }
        
        //If there is more victims with deepest metting
        
        if (best_rear_mitting_victims[min(Number_Of_Best_Rear_Metting_Victims - 1, j - 1)].second ==
            best_rear_mitting_victims[0].second)
        {
            int deepest_mitting = best_rear_mitting_victims[0].second;
            
            for (j = 0; j < victims_for_sort.size(); ++j)
                if (victims_for_sort[j].second == deepest_mitting)
                    victims_for_random.push_back(victims_for_sort[j].first);
        }
        else
        {
            for (j = 0; j < Number_Of_Best_Rear_Metting_Victims; ++j)
                if (best_rear_mitting_victims[j].first != NULL)
                    victims_for_random.push_back(best_rear_mitting_victims[j].first);
                else
                    break;
        }
        
        //Now random victim !
        
        int unlucky_number = rand() % victims_for_random.size();
        
        if(victims_for_random[unlucky_number] == NULL)
        {
            fprintf(stderr, "Unlucky number is realy unlucky.\n");
        }
        
        result.push_back(make_pair(hunters[i], victims_for_random[unlucky_number]));
        
        for (vector < PPlayer >::iterator k = victims.begin(); k != victims.end(); ++k)
            if ((*k)->username == victims_for_random[unlucky_number]->username)
            {
                victims.erase(k);
                break;
            }
        
        if (victims.size() <= 0)
        {
            ++i;
            break;
        }
        
        //Перепилить на итераторы всё, если целесообразно.
    }
    
    for (; i < hunters.size(); ++i)
        Remain_Players.push_back(hunters[i]);
    
    for (i = 0; i < victims.size(); ++i)
        Remain_Players.push_back(victims[i]);
    
    return result;
}


//all rendom functions - end

#endif
